#include "representation.h"
#include "histogram.h"
#include <cmath>
#define MAX_TIMES 5000
#define L 256

Representation::Representation() : Filter(){
}

Representation::Representation(Data *_data) : Filter(_data){
}

Representation::~Representation(){
}

bool Representation::isBlackWhite() const{
    Color color;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){

            color = data->getData(i, j);
            if(color.inGrayscale()){
                if((int)color.red == 0) continue;
                if((int)color.red == 255) continue;
                return false;
            }

        }
    }
    return true;
}

Data *Representation::boundaryFollowing(){

    int pad = 3;
    Color color;
    data = padding(pad, pad);
    Data *newData = new Data(data->getWidth(), data->getHeight());



    int ci = -1, cj = -1, bi = -1, bj = -1, cx0 = -1, cy0 = -1, bx0 = -1, by0 = -1, n = 0;
    bool finded = false;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){

            color = data->getData(i, j);
            if((int)color.red == 255){
                bx0 = i;
                by0 = j;
                cx0 = i;
                cy0 = j - 1;

                newData->setData(i, j, color);
                finded = true;
                break;
            }

        }
        if(finded) break;
    }


    bool change = true;
    int position = 0;
    bi = cx0;
    bj = cy0;
    /*
    posição é definida como:
    1 2 3
    0 . 4
    7 6 5
    */

//    std::cout << "cx0: " << cx0 << "\tcy0: " << cy0 << "\tbx0" << bx0 << "\tby0" <<by0 <<std::endl;

    while( !(ci == cx0 && cj == cy0 && bi == bx0 && bj == by0)){// || (n < MAX_TIMES*(data->getWidth() * data->getHeight()))){

//int nhe;
//std::cin >> nhe;

//            std::cout << "position Antes: " << position;
        if(change){
//            std::cout << "\tchanged! ";
            ci = bi;
            cj = bj;
        }else{
//            std::cout << "\tnot changed! ";
            bi = ci;
            bj = cj;
            change = true;
        }

        switch(position){
            case 0:{
                bi--;
                position = 1;
                break;
            }
            case 1:{
                bj++;
                position = 2;
                break;
            }
            case 2:{
                bj++;
                position = 3;
                break;
            }
            case 3:{
                bi++;
                position = 4;
                break;
            }
            case 4:{
                bi++;
                position = 5;
                break;
            }
            case 5:{
                bj--;
                position = 6;
                break;
            }
            case 6:{
                bj--;
                position = 7;
                break;
            }
            case 7:{
                bi--;
                position = 0;
                break;
            }
        }

//            std::cout << "\tposition Depois: " << position << "\tcx0: " << cx0 << "\tcy0: " << cy0 << "\tbx0" << bx0 << "\tby0" <<by0 <<std::endl;

        color = data->getData(bi, bj);
        if((int)color.red == 255){
            newData->setData(bi, bj, color);
            change = false;

            switch(position){
                case 0:{
                    position = 6;
                    break;
                }
                case 1:{
                    position = 6;
                    break;
                }
                case 2:{
                    position = 0;
                    break;
                }
                case 3:{
                    position = 0;
                    break;
                }
                case 4:{
                    position = 2;
                    break;
                }
                case 5:{
                    position = 2;
                    break;
                }
                case 6:{
                    position = 4;
                    break;
                }
                case 7:{
                    position = 4;
                    break;
                }
            }
        }

        n++;
//        std::cout << "\n\nn: " << n  << "\t\tdata->getHeight() :" << MAX_TIMES <<"-----   "<< (unsigned int)MAX_TIMES*data->getWidth()* data->getHeight()<<std::endl;

        if((unsigned int)n > (unsigned int)MAX_TIMES*(data->getWidth() * data->getHeight())){
            std::cout <<"Algo deu errado" <<std::endl;
            break;
        }
    }

    delete data;
    data = newData;
    data = cropping(pad, pad);
    return data;
}

Data *Representation::chainCode(int _type, std::string *_chainCode, std::string *_firstDifference, std::string */*_shapeNumber*/){
    //type = 0 << vizinhança 4
    //type = 1 << vizinhança 8

//    int resampling = 2;
//    ipegar parte inteira de um doublent padX = resampling - (data->getWidth() % resampling);
//    int padY = resampling - (data->getHeight() % resampling);
//
//    data = padding(padX, padY);
//    Data *newData = new Data(data->getWidth() / resampling, data->getHeight() / resampling);
////    std::cout << "novo w: " << data->getWidth() / 3 << "\tnovo h:" << data->getHeight() / 3 << std::endl;
//    data = cropping(padX, padY);
//
//
//    for(int i = 0; i < newData->getWidth(); i++){
//        for(int j = 0; j < newData->getHeight(); j++){
//        }
//    }

    //deixa somente a borda
    data = boundaryFollowing();


    Color c;
    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){
            c = data->getData(i, j);
            if((int)c.red == 255) std::cout << " 1";
            else if((int)c.red == 0) std::cout << " 0";
            else  std::cout << " x";
        }
         std::cout <<std::endl;
    }

//
//    int nhe;
//    std::cin >> nhe;

    std::string result = "";
    Color color;

    int ci = -1, cj = -1, bi = -1, bj = -1, cx0 = -1, cy0 = -1, bx0 = -1, by0 = -1, n = 0;
    bool finded = false;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){

            color = data->getData(i, j);
            if((int)color.red == 255){
                bx0 = i;
                by0 = j;
                cx0 = i;
                cy0 = j - 1;

                finded = true;
                break;
            }

        }
        if(finded) break;
    }


    /*
    posição é definida como:
    1 2 3
    0 . 4
    7 6 5
    */

    int current = 4;
    int previous = -1;
    bool change = true;
    int position = 0;
    bi = cx0;
    bj = cy0;
//    char intToChar[8];
//    intToChar[0] = '0';
//    intToChar[1] = '1';
//    intToChar[2] = '2';
//    intToChar[3] = '3';
//    intToChar[4] = '4';
//    intToChar[5] = '5';
//    intToChar[6] = '6';
//    intToChar[7] = '7';
//    finded = false;
    if(_type == 1){//direção 8
        while( !(ci == cx0 && cj == cy0 && bi == bx0 && bj == by0)){

            if(change){
                ci = bi;
                cj = bj;
            }else{
                bi = ci;
                bj = cj;
                change = true;
            }

            switch(position){
                case 0:{
                    bi--;
                    position = 1;
                    current = 3;
                    break;
                }
                case 1:{
                    bj++;
                    position = 2;
                    current = 2;
                    break;
                }
                case 2:{
                    bj++;
                    position = 3;
                    current = 1;
                    break;
                }
                case 3:{
                    bi++;
                    position = 4;
                    current = 0;
                    break;
                }
                case 4:{
                    bi++;
                    position = 5;
                    current = 7;
                    break;
                }
                case 5:{
                    bj--;
                    position = 6;
                    current = 6;
                    break;
                }
                case 6:{
                    bj--;
                    position = 7;
                    current = 5;
                    break;
                }
                case 7:{
                    bi--;
                    position = 0;
                    current = 4;
                    break;
                }
            }


            color = data->getData(bi, bj);
            if((int)color.red == 255){
                change = false;
                (*_chainCode) += intToStr(current);
                if(previous != -1){
                    if(previous > current) (*_firstDifference) += intToStr(8 - (previous - current));
                    else (*_firstDifference) += intToStr(current - previous);
                }
                previous = current;

                switch(position){
                    case 0:{
                        position = 6;
                        break;
                    }
                    case 1:{
                        position = 6;
                        break;
                    }
                    case 2:{
                        position = 0;
                        break;
                    }
                    case 3:{
                        position = 0;
                        break;
                    }
                    case 4:{
                        position = 2;
                        break;
                    }
                    case 5:{
                        position = 2;
                        break;
                    }
                    case 6:{
                        position = 4;
                        break;
                    }
                    case 7:{
                        position = 4;
                        break;
                    }
                }
            }

            n++;
        }
    }


    return data;
}

std::vector<Point> Representation::splitting(int _depth, std::string *_s){
    std::vector< Point > points;
    Point current;
    int a = -1, b = -1;//posição de a e b na lista
    double maxDist = -1.0, currentDist = -1.0;

    int pad = 3;
    Color color;
    data = padding(pad, pad);


    //achando o primeiro
    int ci = -1, cj = -1, bi = -1, bj = -1, cx0 = -1, cy0 = -1, bx0 = -1, by0 = -1, n = 0;
    bool finded = false;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){

            color = data->getData(i, j);
            if((int)color.red == 255){
                bx0 = i;
                by0 = j;
                cx0 = i;
                cy0 = j - 1;

                finded = true;
                break;
            }

        }
        if(finded) break;
    }

    bool change = true;
    int position = 0;
    bi = cx0;
    bj = cy0;
    points.push_back(Point(bx0, by0));
    /*
    posição é definida como:
    1 2 3
    0 . 4
    7 6 5
    */

//    std::cout << "cx0: " << cx0 << "\tcy0: " << cy0 << "\tbx0" << bx0 << "\tby0" <<by0 <<std::endl;

    while( !(ci == cx0 && cj == cy0 && bi == bx0 && bj == by0)){// || (n < MAX_TIMES*(data->getWidth() * data->getHeight()))){

//int nhe;
//std::cin >> nhe;

//            std::cout << "position Antes: " << position;
        if(change){
//            std::cout << "\tchanged! ";
            ci = bi;
            cj = bj;
        }else{
//            std::cout << "\tnot changed! ";
            bi = ci;
            bj = cj;
            change = true;
        }

        switch(position){
            case 0:{
                bi--;
                position = 1;
                break;
            }
            case 1:{
                bj++;
                position = 2;
                break;
            }
            case 2:{
                bj++;
                position = 3;
                break;
            }
            case 3:{
                bi++;
                position = 4;
                break;
            }
            case 4:{
                bi++;
                position = 5;
                break;
            }
            case 5:{
                bj--;
                position = 6;
                break;
            }
            case 6:{
                bj--;
                position = 7;
                break;
            }
            case 7:{
                bi--;
                position = 0;
                break;
            }
        }

//            std::cout << "\tposition Depois: " << position << "\tcx0: " << cx0 << "\tcy0: " << cy0 << "\tbx0" << bx0 << "\tby0" <<by0 <<std::endl;

        color = data->getData(bi, bj);
        if((int)color.red == 255){
            change = false;
            //achando o proximo ponto

            //testa contra todos os outros pontos para ver os dois de maior distancia
            for(unsigned int i = 0; i < points.size(); i++){
                current = points.at(i);
                currentDist = (current - Point(bi, bj)).length();
                if(currentDist > maxDist){
                    maxDist = currentDist;
                    a = points.size();
                    b = i;
                }
            }
            //coloca ele na lista
            points.push_back(Point(bi, bj));

            switch(position){
                case 0:{
                    position = 6;
                    break;
                }
                case 1:{
                    position = 6;
                    break;
                }
                case 2:{
                    position = 0;
                    break;
                }
                case 3:{
                    position = 0;
                    break;
                }
                case 4:{
                    position = 2;
                    break;
                }
                case 5:{
                    position = 2;
                    break;
                }
                case 6:{
                    position = 4;
                    break;
                }
                case 7:{
                    position = 4;
                    break;
                }
            }
        }

        n++;
//        std::cout << "\n\nn: " << n  << "\t\tdata->getHeight() :" << MAX_TIMES <<"-----   "<< (unsigned int)MAX_TIMES*data->getWidth()* data->getHeight()<<std::endl;

        if((unsigned int)n > (unsigned int)MAX_TIMES*(data->getWidth() * data->getHeight())){
            std::cout <<"Algo deu errado" <<std::endl;
            break;
        }
    }
    points.pop_back();//removendo o ultimo que é igual ao primeiro


    std::vector<Point> chosenPoints;
    //o ultimo é igual ao priemiro mas deixa para melhor usar o recursivo.
    current = points.at(a);
    chosenPoints.push_back(current);
    splittingRecursive(_depth - 1, points, &chosenPoints, a, b);

    current = points.at(b);
    chosenPoints.push_back(current);
    splittingRecursive(_depth - 1, points, &chosenPoints, b, a);

    for(unsigned int i = 0; i < chosenPoints.size(); i++){
        current = chosenPoints.at(i);
        (*_s) += "( ";
        (*_s) += intToStr(current.x);
        (*_s) += ", ";
        (*_s) += intToStr(current.y);
        (*_s) += " )\n";
    }

    data = cropping(pad, pad);
    return chosenPoints;
}

std::vector<Point> Representation::getAllPoints(){
    std::vector< Point > points;
    Point current;
    int a = -1, b = -1;//posição de a e b na lista
    double maxDist = -1.0, currentDist = -1.0;

    int pad = 3;
    Color color;
    data = padding(pad, pad);


//        std::cout << "em pegnaod os pontos, antes de ahcar o primeiro!" <<std::endl;
    //achando o primeiro
    int ci = -1, cj = -1, bi = -1, bj = -1, cx0 = -1, cy0 = -1, bx0 = -1, by0 = -1, n = 0;
    bool finded = false;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){

            color = data->getData(i, j);
            if((int)color.red == 255){
                bx0 = i;
                by0 = j;
                cx0 = i;
                cy0 = j - 1;

                finded = true;
                break;
            }

        }
        if(finded) break;
    }

    bool change = true;
    int position = 0;
    bi = cx0;
    bj = cy0;
    points.push_back(Point(bx0, by0));
    /*
    posição é definida como:
    1 2 3
    0 . 4
    7 6 5
    */

//    std::cout << "cx0: " << cx0 << "\tcy0: " << cy0 << "\tbx0" << bx0 << "\tby0" <<by0 <<std::endl;

//        std::cout << "em pegnaod os pontos, antes do while!" <<std::endl;
    while( !(ci == cx0 && cj == cy0 && bi == bx0 && bj == by0)){// || (n < MAX_TIMES*(data->getWidth() * data->getHeight()))){

//int nhe;
//std::cin >> nhe;

//            std::cout << "position Antes: " << position;
        if(change){
//            std::cout << "\tchanged! ";
            ci = bi;
            cj = bj;
        }else{
//            std::cout << "\tnot changed! ";
            bi = ci;
            bj = cj;
            change = true;
        }

        switch(position){
            case 0:{
                bi--;
                position = 1;
                break;
            }
            case 1:{
                bj++;
                position = 2;
                break;
            }
            case 2:{
                bj++;
                position = 3;
                break;
            }
            case 3:{
                bi++;
                position = 4;
                break;
            }
            case 4:{
                bi++;
                position = 5;
                break;
            }
            case 5:{
                bj--;
                position = 6;
                break;
            }
            case 6:{
                bj--;
                position = 7;
                break;
            }
            case 7:{
                bi--;
                position = 0;
                break;
            }
        }

//            std::cout << "\tposition Depois: " << position << "\tcx0: " << cx0 << "\tcy0: " << cy0 << "\tbx0" << bx0 << "\tby0" <<by0 <<std::endl;

        color = data->getData(bi, bj);
        if((int)color.red == 255){
            change = false;
            //achando o proximo ponto

            //testa contra todos os outros pontos para ver os dois de maior distancia
            for(unsigned int i = 0; i < points.size(); i++){
                current = points.at(i);
                currentDist = (current - Point(bi, bj)).length();
                if(currentDist > maxDist){
                    maxDist = currentDist;
                    a = points.size();
                    b = i;
                }
            }
            //coloca ele na lista
            points.push_back(Point(bi, bj));

            switch(position){
                case 0:{
                    position = 6;
                    break;
                }
                case 1:{
                    position = 6;
                    break;
                }
                case 2:{
                    position = 0;
                    break;
                }
                case 3:{
                    position = 0;
                    break;
                }
                case 4:{
                    position = 2;
                    break;
                }
                case 5:{
                    position = 2;
                    break;
                }
                case 6:{
                    position = 4;
                    break;
                }
                case 7:{
                    position = 4;
                    break;
                }
            }
        }

        n++;
//        std::cout << "\n\nn: " << n  << "\t\tdata->getHeight() :" << MAX_TIMES <<"-----   "<< (unsigned int)MAX_TIMES*data->getWidth()* data->getHeight()<<std::endl;

        if((unsigned int)n > (unsigned int)MAX_TIMES*(data->getWidth() * data->getHeight())){
            std::cout <<"Algo deu errado" <<std::endl;
            break;
        }
    }
    points.pop_back();//removendo o ultimo que é igual ao primeiro

    return points;
}

void Representation::splittingRecursive(int _depth, std::vector< Point > _points, std::vector< Point > *_chosenPoints, int _a, int _b){
//    double maxCosAlpha = -1, currentCosAlpha = -1; //tendo o maior cosseno teremos o menor angulo
    double maxDist = -1, currentDist = -1;
    int c = -1;
    Point current, v, pq;
//    std::cout <<"Começando com A(" << _points.at(_a).x << ", " << _points.at(_a).y << ")   e   B(" << _points.at(_b).x << ", " << _points.at(_b).y << ")" <<std::endl;
    if(_depth > 0){
        //calcula a distancia de todos os pontos entre a e b
        //o de maior distancia é um ponto escolhido
        if(_a < _b){
            for(int i = _a + 1; i < _b; i++){
                current = _points.at(i);
//                currentCosAlpha = cosAlpha(_points.at(_a), _points.at(_b), current);
                v = current - _points.at(_a);
                pq = _points.at(_b) - _points.at(_a);
                currentDist = (pq).crossProductLength(v) / pq.length();

//                std::cout << "c(" << current.x << ", " << current.y << ") \tdistancia: " << currentDist << "\t\tMAX: " << maxDist <<std::endl;

                if(currentDist > maxDist){
                    maxDist = currentDist;
                    c = i;
                }
            }
        }else{
            for(unsigned int i = _a + 1; i < _points.size(); i++){
                current = _points.at(i);
//                currentCosAlpha = cosAlpha(_points.at(_a), _points.at(_b), current);
                v = current - _points.at(_a);
                pq = _points.at(_b) - _points.at(_a);
                currentDist = (pq).crossProductLength(v) / pq.length();

//                std::cout << "c(" << current.x << ", " << current.y << ") \tdistancia: " << currentDist << "\t\tMAX: " << maxDist <<std::endl;

                if(currentDist > maxDist){
                    maxDist = currentDist;
                    c = i;
                }
            }
            for(int i = 0; i < _b; i++){
                current = _points.at(i);
//                currentCosAlpha = cosAlpha(_points.at(_a), _points.at(_b), current);
                v = current - _points.at(_a);
                pq = _points.at(_b) - _points.at(_a);
                currentDist = (pq).crossProductLength(v) / pq.length();


//                std::cout << "c(" << current.x << ", " << current.y << ") \tdistancia: " << currentDist << "\t\tMAX: " << maxDist <<std::endl;

                if(currentDist > maxDist){
                    maxDist = currentDist;
                    c = i;
                }
            }
        }
//        int nhe;
//        std::cin >> nhe;

        if(c == -1) return;


        //faz recursivamente de a até ele,
        splittingRecursive(_depth - 1, _points, _chosenPoints, _a, c);


        //acrescenta o ponto a s (que foi modificado do recursivo anterior)
        current = _points.at(c);
        _chosenPoints->push_back(current);

        //faz o revursivo dele a b
        splittingRecursive(_depth - 1, _points, _chosenPoints, c, _b);

    }
}

void Representation::basicDescriptors(std::string *_perimeter, std::string *_area, std::string *_diameter, std::string *_compactness, std::string *_circularRatio){

    int perimeter = 0; //porque conta o mesmo primeiro pixel duas vezes
    int area = 0;
    double diameter = 0;
    double compactness = 0;
    double circularRatio = 0;
    data = boundaryFollowing();



    std::vector< Point > points;
    Point current;
    double maxDist = -1.0, currentDist = -1.0;

    int pad = 3;
    Color color;
    data = padding(pad, pad);
    Data *newData = new Data(data->getWidth(), data->getHeight());

    Color c;
    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){
            c = data->getData(i, j);
            if((int)c.red == 255) std::cout << " 1";
            else if((int)c.red == 0) std::cout << " 0";
            else  std::cout << " x";
        }
         std::cout <<std::endl;
    }

    int ci = -1, cj = -1, bi = -1, bj = -1, cx0 = -1, cy0 = -1, bx0 = -1, by0 = -1, n = 0;
    bool finded = false;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){

            color = data->getData(i, j);
            if((int)color.red == 255){
                bx0 = i;
                by0 = j;
                cx0 = i;
                cy0 = j - 1;

                newData->setData(i, j, color);
                finded = true;
                break;
            }

        }
        if(finded) break;
    }


    bool change = true;
    int position = 0;
    bi = cx0;
    bj = cy0;
    Point a, b;
    points.push_back(Point(bx0, by0));
    /*
    posição é definida como:
    1 2 3
    0 . 4
    7 6 5
    */


    while( !(ci == cx0 && cj == cy0 && bi == bx0 && bj == by0)){// || (n < MAX_TIMES*(data->getWidth() * data->getHeight()))){

        if(change){
            ci = bi;
            cj = bj;
        }else{
            bi = ci;
            bj = cj;
            change = true;
        }

        switch(position){
            case 0:{
                bi--;
                position = 1;
                break;
            }
            case 1:{
                bj++;
                position = 2;
                break;
            }
            case 2:{
                bj++;
                position = 3;
                break;
            }
            case 3:{
                bi++;
                position = 4;
                break;
            }
            case 4:{
                bi++;
                position = 5;
                break;
            }
            case 5:{
                bj--;
                position = 6;
                break;
            }
            case 6:{
                bj--;
                position = 7;
                break;
            }
            case 7:{
                bi--;
                position = 0;
                break;
            }
        }
        color = data->getData(bi, bj);
        if((int)color.red == 255){
            newData->setData(bi, bj, color);
            change = false;
//std::cout << "n " << n<<"\tnaum deu pau ainda " << points.size() <<std::endl;

            //testa contra todos os outros pontos para ver os dois de maior distancia
            for(unsigned int i = 0; i < points.size(); i++){
//std::cout <<"i: " << i<<std::endl;
                current = points.at(i);
                currentDist = (current - Point(bi, bj)).length();
                if(currentDist > maxDist){
                    maxDist = currentDist;
                    a = current;
                    b = Point(bi, bj);
                }
            }
            //coloca ele na lista
            points.push_back(Point(bi, bj));

            perimeter++;

            switch(position){
                case 0:{
                    position = 6;
                    break;
                }
                case 1:{
                    position = 6;
                    break;
                }
                case 2:{
                    position = 0;
                    break;
                }
                case 3:{
                    position = 0;
                    break;
                }
                case 4:{
                    position = 2;
                    break;
                }
                case 5:{
                    position = 2;
                    break;
                }
                case 6:{
                    position = 4;
                    break;
                }
                case 7:{
                    position = 4;
                    break;
                }
            }
        }

        n++;
        if((unsigned int)n > (unsigned int)MAX_TIMES*(data->getWidth() * data->getHeight())){
            std::cout <<"Algo deu errado" <<std::endl;
            break;
        }
    }
            std::cout <<"A(" << a.x <<", " << a.y<<") \tB(" << b.x <<", " << b.y << ")" <<std::endl;
    points.pop_back();//removendo o ultimo que é igual ao primeiro
    diameter = maxDist;

    bool inside = false;
    int j1, j2;
    for(int i = 0; i < newData->getWidth(); i++){

//        std::cout << "i : " <<i <<std::endl;
        j1 = 0;
        while(newData->getData(i, j1).red != 255){
            j1++;
//            std::cout << "\t j1 : " << j1 << "\t\tnewData->getHeight() -1:" <<newData->getHeight() -1 <<std::endl;
            if (j1 >= newData->getHeight() -1) break;
        }
//            std::cout << "saiu" <<std::endl;

        j2 = newData->getHeight() - 1;
        while(newData->getData(i, j2).red != 255){
            j2--;
//            std::cout << "\t j2 : " << j2 <<std::endl;
            if (j2 <= 0) break;
        }

        inside = true;
        if(newData->getData(i-1, j1+1).red != 255) inside = false;

        while(j1 < j2){
            j1++;
            if(newData->getData(i, j1).red != 255){
                if(inside) newData->setData(i, j1, Color(255., 255., 255.));
            }else{
                inside = true;
                if(newData->getData(i-1, j1+1).red != 255) inside = false;
            }
        }

    }
    for(int i = 0; i < newData->getWidth(); i++){
        for(int j = 0; j < newData->getHeight(); j++){
            color = newData->getData(i, j);
            if((int)color.red == 255) area++;
        }
    }

    compactness = ((double)perimeter*perimeter) / ((double)area);
    circularRatio = (4.0 * M_PI * area) / ((double)perimeter*perimeter);


    *_perimeter = intToStr(perimeter);
    *_area = intToStr(area);
    *_diameter = doubleToStr(diameter);
    *_compactness = doubleToStr(compactness);
    *_circularRatio = doubleToStr(circularRatio);

}

void Representation::momentInvariantsDescriptors(std::string *_m1, std::string *_m2, std::string *_m3, std::string *_m4, std::string *_m5, std::string *_m6, std::string *_m7){

        double n11 = normalizedCentralMoment(1,1);

        double n20 = normalizedCentralMoment(2,0);
        double n02 = normalizedCentralMoment(0,2);

        double n30 = normalizedCentralMoment(3,0);
        double n03 = normalizedCentralMoment(0,3);

        double n12 = normalizedCentralMoment(1,2);
        double n21 = normalizedCentralMoment(2,1);

        *_m1 = doubleToStr( n20 + n02 );
        *_m2 = doubleToStr( ((n20 - n02)*(n20 - n02)) + (4*n11*n11) );
        *_m3 = doubleToStr( ((n30 - (3*n12))*(n30 - (3*n12))) + (((3*n21) - n03)*((3*n21) - n03)) );
        *_m4 = doubleToStr( ((n30 + n12)*(n30 + n12)) + ((n21 + n03)*(n21 + n03)) );
        *_m5 = doubleToStr( ((n30 - (3*n12))*(n30 + n12)*( ((n30 + n12)*(n30 + n12)) - (3*((n21 + n03)*(n21 + n03))) ))
                          + (((3*n21) - n03)*(n21 + n03)*( (3*((n30 + n12)*(n30 + n12))) - ((n21 + n03)*(n21 + n03)) )) );
        *_m6 = doubleToStr( ( (n20 - n02)*( ((n30 + n12)*(n30 + n12)) - ((n21 + n03)*(n21 + n03))) ) + (4*n11*(n30 + n12)*(n21 + n03)) );
//        *_m7 = doubleToStr( (((3*n21) - n03)*(n30 + n12)*( ((n30 + n12)*(n30 + n12)) - (3*((n21 + n03)*(n21 + n03))) ))
//                          + (((3*n12) - n30)*(n21 + n30)*( (3*((n30 + n12)*(n30 + n12))) - ((n21 + n03)*(n21 + n03)) )) );
        *_m7 = doubleToStr( (((3*n21) - n03)*(n30 + n12)*( ((n30 + n12)*(n30 + n12)) - (3*((n21 + n03)*(n21 + n03))) ))
                          - ((n30 - (3*n12))*(n21 + n30)*( (3*((n30 + n12)*(n30 + n12))) - ((n21 + n03)*(n21 + n03)) )) );
}

double Representation::moment(int _p, int _q){
    double result = 0;
    Color color;


    double y0 = 0.;
    double yn = 1.;
    double x0 = 0.;
    double xn = 255.;
    double value;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){
            color = data->getData(i, j);
            value = normalize2(x0, xn, y0, yn, (double)color.red) ;
//            std::cout << "normal: " << value << "\tnormalizado: " << (double)normalize2(x0, xn, y0, yn, value) << std::endl;
            result += pow(i, _p)*pow(j, _q)*(value);
        }
    }

    return result;
}

double Representation::centralMoment(int _p, int _q){
    double m00 = moment(0,0);
    double x_ = moment(1,0) / m00;
    double y_ = moment(0,1) / m00;

    double result = 0;
    Color color;

    double y0 = 0.;
    double yn = 1.;
    double x0 = 0.;
    double xn = 255.;
    double value;

    for(int i = 0; i < data->getWidth(); i++){
        for(int j = 0; j < data->getHeight(); j++){
            color = data->getData(i, j);
            value = normalize2(x0, xn, y0, yn, (double)color.red) ;
            result += pow((i - x_), _p)*pow((j - y_), _q)*(value);
        }
    }

    return result;
}

double Representation::normalizedCentralMoment(int _p, int _q){
    return centralMoment(_p, _q) / pow(centralMoment(0, 0), omega(_p, _q));
}

double Representation::omega(int _p, int _q){
    return (((double)(_p + _q))/2.0) + 1.0;
}

void Representation::histogramDescriptors(std::string *_m1, std::string *_m2, std::string *_m3, std::string *_m4, std::string *_m5, std::string *_m6){
    Histogram histogram = Histogram(data);
    double variance = histogram.getVariance();


    *_m1 = doubleToStr( histogram.getMean() );//media
    *_m2 = doubleToStr( sqrt(variance) );//desvio padrão
    *_m3 = doubleToStr( 1 - ( 1.0 / (1 + (variance/((L - 1)*(L - 1))) ) ) );//r normalizado
    *_m4 = doubleToStr( histogram.thirdMoment() );//r terceiro momento
    *_m5 = doubleToStr( histogram.uniformity() );//r terceiro momento
    *_m6 = doubleToStr( histogram.entropy() );//r terceiro momento
}

